import express, { Request, Response } from 'express';
import fetch from 'node-fetch';

const router = express.Router();

// AI配置接口
interface AIConfig {
  provider: 'openai' | 'deepseek' | 'claude' | 'tongyi' | 'doubao' | 'custom';
  apiKey: string;
  model: string;
  baseUrl?: string;
  temperature?: number;
  maxTokens?: number;
  priority?: number;
  enabled?: boolean;
  maxRetries?: number;
}

interface MultiAIConfig {
  models: AIConfig[];
  autoSwitch: boolean;
  fallbackOnError: boolean;
  fallbackOnQuotaExhausted: boolean;
}

interface AICallResult {
  content: string;
  tokens: number;
  usedModel?: AIConfig;
  attempts?: number;
}

// Git提交记录接口（与git.ts保持一致）
interface GitCommit {
  hash: string;
  author: string;
  email: string;
  date: Date;
  message: string;
  files: FileChange[];
  additions: number;
  deletions: number;
}

interface FileChange {
  path: string;
  status: 'added' | 'modified' | 'deleted' | 'renamed';
  additions: number;
  deletions: number;
  oldPath?: string;
  diff?: string; // 添加diff字段
}

// Git变更记录接口（从前端传递过来的数据格式）
interface GitChange {
  file: string;
  type: 'added' | 'modified' | 'deleted';
  additions: number;
  deletions: number;
  diff: string; // 包含实际的代码diff内容
  commit: {
    hash: string;
    message: string;
    author: string;
    date: Date;
  };
}

/**
 * AI服务代理接口
 * 用于解决前端CORS跨域问题
 */
router.post('/proxy', async (req: Request, res: Response) => {
  try {
    const { url, headers, body, method = 'POST' } = req.body;
    
    if (!url) {
      return res.status(400).json({
        success: false,
        error: 'URL is required'
      });
    }

    // 发起代理请求
    const response = await fetch(url, {
      method,
      headers: {
        'Content-Type': 'application/json',
        ...headers
      },
      body: JSON.stringify(body)
    });

    // 检查响应的Content-Type
    const contentType = response.headers.get('content-type');
    let data: any;
    
    try {
      // 尝试解析JSON响应
      if (contentType && contentType.includes('application/json')) {
        data = await response.json();
      } else {
        // 如果不是JSON格式，获取文本内容
        const textContent = await response.text();
        console.warn('API返回非JSON格式响应:', {
          url,
          contentType,
          status: response.status,
          textContent: textContent.substring(0, 500) // 只记录前500字符
        });
        
        // 尝试解析为JSON，如果失败则返回原始文本
        try {
          data = JSON.parse(textContent);
        } catch (parseError) {
          data = {
            error: 'API返回非JSON格式响应',
            content: textContent,
            contentType
          };
        }
      }
    } catch (jsonError: any) {
      console.error('JSON解析失败:', {
        url,
        contentType,
        status: response.status,
        error: jsonError.message
      });
      
      // JSON解析失败时，尝试获取原始文本
      try {
        const textContent = await response.text();
        data = {
          error: 'JSON解析失败',
          content: textContent,
          parseError: jsonError.message
        };
      } catch (textError) {
        data = {
          error: 'JSON解析失败且无法获取文本内容',
          parseError: jsonError.message,
          textError: textError.message
        };
      }
    }
    
    if (!response.ok) {
      return res.status(response.status).json({
        success: false,
        error: data,
        status: response.status
      });
    }

    res.json({
      success: true,
      data
    });
  } catch (error: any) {
    console.error('AI代理请求失败:', error);
    res.status(500).json({
      success: false,
      error: error.message || '代理请求失败'
    });
  }
});

/**
 * 生成AI报告
 * POST /api/ai/reports/generate
 */
router.post('/reports/generate', async (req: Request, res: Response) => {
  try {
    const { commits, model, apiKey, type, aiConfig, multiConfig, style, format, customPrompt } = req.body;

    if (!commits || !Array.isArray(commits) || commits.length === 0) {
      return res.status(400).json({
        success: false,
        error: '没有Git提交记录，无法生成报告。请确认项目路径正确且在指定时间范围内有代码提交。'
      });
    }

    // 优先使用多AI配置，如果没有则使用单一配置
    let finalConfig: AIConfig | MultiAIConfig;
    if (multiConfig && multiConfig.autoSwitch && multiConfig.models && multiConfig.models.length > 0) {
      finalConfig = multiConfig;
      console.log('使用多AI配置，启用自动切换');
    } else if (apiKey && model) {
      finalConfig = {
        apiKey,
        model,
        provider: aiConfig?.provider || 'deepseek',
        baseUrl: aiConfig?.baseUrl,
        temperature: aiConfig?.temperature || 0.7,
        maxTokens: aiConfig?.maxTokens || 4000 // 增加token限制以容纳diff内容
      };
      console.log('使用单一AI配置');
    } else {
      return res.status(400).json({
        success: false,
        error: 'API密钥和模型不能为空，或需要提供有效的多AI配置'
      });
    }

    // 构建报告内容（现在支持GitChange格式，包含diff内容）
    const reportContent = await generateReport(commits, type, finalConfig, style, format, customPrompt);

    res.json({
      success: true,
      content: reportContent.content,
      tokens: reportContent.tokens
    });
  } catch (error: any) {
    console.error('生成AI报告失败:', error);
    res.status(500).json({
      success: false,
      error: `生成报告失败: ${error.message}`
    });
  }
});

/**
 * 生成手动输入内容的AI报告
 * POST /api/ai/reports/manual
 */
router.post('/reports/manual', async (req: Request, res: Response) => {
  try {
    const { content, reportType, style, enablePolish, model, apiKey, aiConfig, multiConfig, format, customPrompt } = req.body;

    // 添加调试日志
    console.log('🔍 [DEBUG] 接收到的请求参数:');
    console.log('  - reportType:', reportType);
    console.log('  - style:', style);
    console.log('  - enablePolish:', enablePolish);
    console.log('  - format:', format);
    console.log('  - content length:', content?.length);

    if (!content || typeof content !== 'string' || content.trim() === '') {
      return res.status(400).json({
        success: false,
        error: '工作内容不能为空'
      });
    }

    // 优先使用多AI配置，如果没有则使用单一配置
    let finalConfig: AIConfig | MultiAIConfig;
    if (multiConfig && multiConfig.autoSwitch && multiConfig.models && multiConfig.models.length > 0) {
      finalConfig = multiConfig;
      console.log('使用多AI配置，启用自动切换');
    } else if (apiKey && model) {
      finalConfig = {
        apiKey,
        model,
        provider: aiConfig?.provider || 'deepseek',
        baseUrl: aiConfig?.baseUrl,
        temperature: aiConfig?.temperature || 0.7,
        maxTokens: aiConfig?.maxTokens || 3000
      };
      console.log('使用单一AI配置');
    } else {
      return res.status(400).json({
        success: false,
        error: 'API密钥和模型不能为空，或需要提供有效的多AI配置'
      });
    }

    console.log('🔍 [DEBUG] 传递给generateManualReport的reportType:', reportType);

    // 生成手动输入内容的报告
    const reportContent = await generateManualReport(content, reportType, finalConfig, style, enablePolish, format, customPrompt);

    res.json({
      success: true,
      content: reportContent.content,
      tokens: reportContent.tokens
    });
  } catch (error: any) {
    console.error('生成手动报告失败:', error);
    res.status(500).json({
      success: false,
      error: `生成手动报告失败: ${error.message}`
    });
  }
});

/**
 * 生成报告内容
 */
async function generateReport(
  commits: GitCommit[] | GitChange[], 
  type: string, 
  config: AIConfig | MultiAIConfig,
  style?: string,
  format?: string,
  customPrompt?: string
): Promise<{ content: string; tokens: number }> {
  // 如果commits数量较少，直接处理
  if (commits.length <= 20) {
    const prompt = buildReportPrompt(commits, type, style, format, customPrompt);
    if (isMultiAIConfig(config)) {
      const smartResult = await callSmartAI(prompt, config, format);
      return { content: smartResult.content, tokens: smartResult.tokens };
    } else {
      return await callAIAPI(prompt, config, format);
    }
  }
  
  // 如果commits数量很多，使用分批处理策略
  console.log(`[AI报告生成] 检测到大量commits (${commits.length}个)，启用分批处理策略`);
  
  const batchSize = 15; // 每批处理15个commits
  const batches: (GitCommit[] | GitChange[])[] = [];
  
  // 将commits分成多个批次
  for (let i = 0; i < commits.length; i += batchSize) {
    batches.push(commits.slice(i, i + batchSize));
  }
  
  console.log(`[AI报告生成] 分成${batches.length}个批次处理`);
  
  // 并行处理所有批次
  const batchResults = await Promise.all(
    batches.map(async (batch, index) => {
      console.log(`[AI报告生成] 处理第${index + 1}批次 (${batch.length}个commits)`);
      const prompt = buildReportPrompt(batch, type, style, format, customPrompt);
      if (isMultiAIConfig(config)) {
        const smartResult = await callSmartAI(prompt, config, format);
        return { content: smartResult.content, tokens: smartResult.tokens };
      } else {
        return await callAIAPI(prompt, config, format);
      }
    })
  );
  
  // 合并所有批次的结果
  const mergedContent = await mergeBatchResults(batchResults, type, config, style, format);
  
  // 计算总token使用量
  const totalTokens = batchResults.reduce((sum, result) => sum + result.tokens, 0);
  
  console.log(`[AI报告生成] 分批处理完成，总计使用${totalTokens}个tokens`);
  
  return {
    content: mergedContent,
    tokens: totalTokens
  };
}

/**
 * 生成手动输入内容的报告
 */
async function generateManualReport(
  content: string,
  reportType: string,
  config: AIConfig | MultiAIConfig,
  style?: string,
  enablePolish?: boolean,
  format?: string,
  customPrompt?: string
): Promise<{ content: string; tokens: number }> {
  // 构建手动输入内容的提示词
  const prompt = buildManualReportPrompt(content, reportType, style, enablePolish, format, customPrompt);
  
  let result: { content: string; tokens: number };
  
  if (isMultiAIConfig(config)) {
    const smartResult = await callSmartAI(prompt, config, format);
    result = { content: smartResult.content, tokens: smartResult.tokens };
  } else {
    // 根据不同的AI服务商调用相应的API
    switch (config.provider) {
      case 'deepseek':
        result = await callDeepSeekAPI(prompt, config);
        break;
      case 'openai':
        result = await callOpenAIAPI(prompt, config);
        break;
      case 'tongyi':
        result = await callTongyiAPI(prompt, config);
        break;
      case 'doubao':
        result = await callDoubaoAPI(prompt, config);
        break;
      default:
        throw new Error(`不支持的AI服务商: ${config.provider}`);
    }
  }
  
  // 如果是纯文本格式，后处理移除所有Markdown语法
  if (format === 'text') {
    result.content = removeMarkdownSyntax(result.content);
  }
  
  return result;
}

/**
 * 移除Markdown语法，确保纯文本输出
 */
function removeMarkdownSyntax(content: string): string {
  return content
    // 移除标题标记
    .replace(/^#{1,6}\s+/gm, '')
    // 移除粗体和斜体
    .replace(/\*\*([^*]+)\*\*/g, '$1')
    .replace(/\*([^*]+)\*/g, '$1')
    .replace(/__([^_]+)__/g, '$1')
    .replace(/_([^_]+)_/g, '$1')
    // 移除代码块
    .replace(/```[\s\S]*?```/g, '')
    .replace(/`([^`]+)`/g, '$1')
    // 移除链接
    .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
    // 移除列表标记
    .replace(/^\s*[-*+]\s+/gm, '• ')
    .replace(/^\s*\d+\.\s+/gm, '')
    // 移除引用
    .replace(/^>\s+/gm, '')
    // 移除水平线
    .replace(/^[-*_]{3,}$/gm, '')
    // 移除表格语法
    .replace(/\|/g, ' ')
    // 清理多余的空行
    .replace(/\n{3,}/g, '\n\n')
    .trim();
}

/**
 * 构建手动输入内容的报告提示词
 */
function buildManualReportPrompt(
  content: string,
  reportType: string,
  style?: string,
  enablePolish?: boolean,
  format?: string,
  customPrompt?: string
): string {
  // 添加调试日志
  console.log('🔍 [DEBUG] buildManualReportPrompt 接收到的参数:');
  console.log('  - reportType:', reportType);
  console.log('  - style:', style);
  console.log('  - enablePolish:', enablePolish);
  console.log('  - format:', format);
  
  const reportTypeText = reportType === 'daily' ? '日报' : '周报';
  const outputFormat = format === 'text' ? '纯文本' : 'Markdown';
  
  console.log('🔍 [DEBUG] 计算得到的reportTypeText:', reportTypeText);
  
  // 根据风格确定写作要求
  const styleRequirements = style === 'professional' 
    ? '使用专业术语，语言正式严谨，重点描述业务功能的实现和用户价值，体现专业性和权威性。'
    : '语言简洁直白，通俗易懂，重点说明完成了什么功能，解决了什么问题，为用户带来了什么价值。';

  // 格式要求
  const formatRequirements = format === 'text' 
    ? '使用纯文本格式，严禁使用任何Markdown语法标记（如#、*、-、**、##、###、```等），用简单的文本结构和空行组织内容，标题用纯文本表示，列表用数字或简单符号。'
    : '使用标准的Markdown格式，包含适当的标题、列表、代码块等格式。';

  // 润色要求
  const polishRequirements = enablePolish 
    ? '对用户输入的内容进行适度润色和优化，但必须保持原意不变，不得夸张或偏离用户输入的主题。润色重点：1) 优化语言表达，使其更加流畅专业；2) 补充必要的业务价值描述；3) 调整结构使其更符合工作报告格式；4) 保持内容的真实性和准确性。'
    : '严格按照用户输入的内容生成报告，不进行润色，保持原始内容的真实性。';

  // 根据报告类型生成特定的模板和要求
  let specificRequirements = '';
  let titleFormat = '';
  
  if (reportType === 'daily') {
    titleFormat = '# 工作日报 - ' + new Date().toLocaleDateString('zh-CN');
    specificRequirements = `
## 🚨 日报特定要求 🚨
- 🔴 严禁生成周报！必须生成日报格式的内容！
- 🔴 标题必须包含"日报"字样，绝对不能包含"周报"字样！
- 重点关注今日完成的具体工作任务
- 总结今日的工作成果和收获
- 规划明日的工作计划
- 时间范围限定在今日（一天）内的工作内容
- 🔴 如果您生成了周报，这将是严重错误！`;
  } else {
    titleFormat = '# 工作周报 - ' + getWeekRange();
    specificRequirements = `
## 🚨 周报特定要求 🚨
- 🔴 严禁生成日报！必须生成周报格式的内容！
- 🔴 标题必须包含"周报"字样，绝对不能包含"日报"字样！
- 重点关注本周完成的主要工作任务
- 总结本周的整体工作成果和进展
- 规划下周的工作计划和目标
- 时间范围限定在本周（一周）内的工作内容
- 🔴 如果您生成了日报，这将是严重错误！`;
  }

  let prompt = `🚨🚨🚨 重要指令 🚨🚨🚨

在开始生成报告之前，请先确认：
- 用户选择的报告类型是：${reportTypeText}
- 您即将生成的是：${reportTypeText}
- 如果不一致，请立即停止并重新确认！

现在请根据以下用户手动输入的工作内容生成一份${reportTypeText}：

## 🚨 严格要求 🚨
**您必须严格生成${reportTypeText}，绝对不能生成其他类型的报告！**
**如果用户选择的是日报，您必须生成日报，标题必须包含"日报"字样！**
**如果用户选择的是周报，您必须生成周报，标题必须包含"周报"字样！**
**当前用户选择的报告类型是：${reportTypeText}**

## 用户输入的工作内容
${content}

## 生成要求
请基于上述工作内容生成一份${reportTypeText}，重点包含以下内容：
1. **工作概述** - 总结主要完成的工作内容
2. **具体成果** - 详细描述完成的具体任务和成果
3. **业务价值** - 分析这些工作对业务或项目的价值和意义
4. **问题解决** - 说明解决了什么问题，优化了什么流程
5. **后续计划** - 基于当前工作合理规划后续任务

${specificRequirements}

## 标题格式要求
报告必须以以下格式开头：
${titleFormat}

## 写作风格要求
${styleRequirements}

## 格式要求
${formatRequirements}

## 润色要求
${polishRequirements}

## 严格要求
- 内容必须基于用户实际输入的工作内容
- 不得添加用户未提及的工作内容
- **🚨 重要：必须严格按照${reportTypeText}的格式生成，标题必须明确标注为${reportTypeText}，绝对不能生成其他类型的报告！🚨**
- ${enablePolish ? '润色时保持内容真实性，避免夸张' : '严格按照用户输入内容，不进行润色'}
- ${format === 'text' ? '输出必须是纯文本，绝对不能包含任何Markdown标记符号' : '使用标准Markdown格式'}
- 语言要${style === 'professional' ? '专业且关注业务价值' : '简洁明了且突出工作亮点'}

## 🔥 最终确认 🔥
**再次确认：您正在生成的是${reportTypeText}，不是其他任何类型的报告！**
**标题必须包含"${reportTypeText === '日报' ? '日报' : '周报'}"字样！**
**请严格遵守以上要求！**`;

  // 如果有自定义提示词，添加到末尾
  if (customPrompt && customPrompt.trim()) {
    prompt += `

## 额外要求
${customPrompt.trim()}`;
  }

  prompt += `

## 🚨 最终检查清单 🚨
在提交您的回答之前，请逐项检查：
✅ 1. 我生成的是${reportTypeText}吗？
✅ 2. 标题包含了正确的"${reportType === 'daily' ? '日报' : '周报'}"字样吗？
✅ 3. 内容符合${reportTypeText}的时间范围要求吗？
✅ 4. 我没有错误地生成${reportType === 'daily' ? '周报' : '日报'}吗？

**如果以上任何一项为否，请立即重新生成！**
**这是强制性要求，违反将被视为严重错误！**`;

  return prompt;
}

// 获取本周日期范围的辅助函数
function getWeekRange(): string {
  const now = new Date();
  const dayOfWeek = now.getDay(); // 0=周日, 1=周一, ..., 6=周六
  
  // 计算本周一的日期
  const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; // 如果是周日，往前推6天到周一；否则计算到周一的偏移
  const startOfWeek = new Date(now.getTime() + mondayOffset * 24 * 60 * 60 * 1000);
  
  // 本周的结束日期就是今天
  const endOfWeek = new Date(now.getTime());
  
  return `${startOfWeek.toLocaleDateString('zh-CN')} - ${endOfWeek.toLocaleDateString('zh-CN')}`;
}

/**
 * 构建报告提示词
 */
function buildReportPrompt(commits: GitCommit[] | GitChange[], type: string, style?: string, format?: string, customPrompt?: string): string {
  // 添加调试日志
  console.log('🔍 [DEBUG] buildReportPrompt 接收到的参数:');
  console.log('  - type:', type);
  console.log('  - style:', style);
  console.log('  - format:', format);
  
  const reportType = type === 'daily' ? '日报' : '周报';
  const outputFormat = format === 'text' ? '纯文本' : 'Markdown';
  
  console.log('🔍 [DEBUG] 计算得到的reportType:', reportType);
  
  // 检测数据格式：GitCommit还是GitChange
  const isGitChangeFormat = commits.length > 0 && 'diff' in commits[0] && 'commit' in commits[0];
  
  let authorStats: any = {};
  let commitDetails: string = '';
  
  if (isGitChangeFormat) {
    // 处理GitChange格式（包含diff内容）
    const gitChanges = commits as GitChange[];
    
    // 按作者分组统计
    const commitsByAuthor = gitChanges.reduce((stats, change) => {
      const author = change.commit.author;
      if (!stats[author]) {
        stats[author] = { commits: new Set(), changes: 0 };
      }
      stats[author].commits.add(change.commit.hash);
      stats[author].changes++;
      return stats;
    }, {} as any);
    
    authorStats = Object.entries(commitsByAuthor).reduce((stats, [author, data]: [string, any]) => {
      stats[author] = { commits: data.commits.size, changes: data.changes };
      return stats;
    }, {} as any);
    
    // 按提交分组构建详细信息
    const commitGroups = gitChanges.reduce((groups, change) => {
      const hash = change.commit.hash;
      if (!groups[hash]) {
        groups[hash] = {
          commit: change.commit,
          changes: []
        };
      }
      groups[hash].changes.push(change);
      return groups;
    }, {} as any);
    
    commitDetails = Object.values(commitGroups).map((group: any) => {
      const { commit, changes } = group;
      let details = `### ${commit.message}\n- 作者: ${commit.author}\n- 时间: ${new Date(commit.date).toLocaleString('zh-CN')}\n- 变更文件: ${changes.length}个\n`;
      
      // 添加每个文件的变更详情和代码diff
      changes.forEach((change: GitChange) => {
        details += `\n#### 文件: ${change.file} (${change.type})\n`;
        details += `- 新增: +${change.additions}行, 删除: -${change.deletions}行\n`;
        
        // 添加代码diff内容（如果存在且不为空）
        if (change.diff && change.diff.trim()) {
          details += `- 代码变更:\n\`\`\`diff\n${change.diff}\n\`\`\`\n`;
        }
      });
      
      return details;
    }).join('\n\n');
    
  } else {
    // 处理传统GitCommit格式（向后兼容）
    const gitCommits = commits as GitCommit[];
    
    authorStats = gitCommits.reduce((stats, commit) => {
      if (!stats[commit.author]) {
        stats[commit.author] = { commits: 0 };
      }
      stats[commit.author].commits++;
      return stats;
    }, {} as any);
    
    commitDetails = gitCommits.map(commit => {
      const files = Array.isArray(commit.files) ? commit.files : [];
      const mainFiles = files
        .filter(file => file && file.path && !file.path.includes('test') && !file.path.includes('spec'))
        .map(file => file.path.split('/').pop() || file.path)
        .slice(0, 3);
      
      return `### ${commit.message}\n- 作者: ${commit.author}\n- 时间: ${new Date(commit.date).toLocaleString('zh-CN')}\n- 主要变更: ${mainFiles.length > 0 ? mainFiles.join(', ') : '无文件变更'}`;
    }).join('\n\n');
  }

  // 根据风格确定写作要求
  const styleRequirements = style === 'professional' 
    ? '使用专业术语，语言正式严谨，重点描述业务功能的实现和用户价值，避免过多技术细节。'
    : '语言简洁直白，通俗易懂，重点说明完成了什么功能，解决了什么问题，为用户带来了什么价值。';

  // 格式要求
  const formatRequirements = format === 'text' 
    ? '使用纯文本格式，严禁使用任何Markdown语法标记（如#、*、-、**、##、###、```等），用简单的文本结构和空行组织内容，标题用纯文本表示，列表用数字或简单符号。'
    : '使用标准的Markdown格式，包含适当的标题、列表、代码块等格式。';

  // 构建基础提示词 - 针对日报和周报使用不同的提示词
  let basePrompt: string;
  
  if (type === 'daily') {
    if (style === 'simple') {
      // 简单风格日报：极简版本，只包含基本信息
      basePrompt = `请根据以下Git提交记录生成一份简洁的${reportType}：

## 提交记录
${commitDetails}

## 生成要求
请生成一份简洁的${reportType}，只包含：
- 今天完成的主要工作（大概概括）
- 涉及的主要功能或模块

## 写作要求
- 语言简洁直白，避免技术术语
- 重点说明完成了什么，解决了什么问题
- 内容控制在100-200字以内
- ${format === 'text' ? '使用纯文本格式，不使用任何标记符号' : '使用简单的Markdown格式'}`;
    } else {
      // 专业风格日报：适度润色版本，基于真实commit记录进行表达优化
      basePrompt = `请根据以下Git提交记录生成一份${reportType}，对今天完成的工作进行适度润色：

## 团队贡献
${Object.entries(authorStats).map(([author, stats]: [string, any]) => {
  if (isGitChangeFormat) {
    return `- ${author}: ${stats.commits}次提交，${stats.changes}个文件变更`;
  } else {
    return `- ${author}: ${stats.commits}次提交`;
  }
}).join('\n')}

## 提交记录
${commitDetails}

## 生成要求
请基于上述提交记录生成一份${reportType}，内容包括：
1. **工作成果总结** - 根据commit message总结今天完成的主要工作，用积极正面的语言表达
2. **技术亮点** - 提炼代码变更中的技术要点和改进，突出工作价值
3. **问题解决** - 如果有bug修复或优化，说明解决了什么问题，带来什么改善
4. **代码变更概览** - 简要说明涉及的主要文件和功能模块

## 润色要求
- 基于真实的commit记录进行适度润色，不夸大不虚构
- 用积极正面的语言表达工作成果，但保持真实性
- 突出工作的技术价值和实际意义，避免过度包装
- 语言专业且有条理，体现工作的专业性和成效

## 写作风格要求
${styleRequirements}

## 格式要求
${formatRequirements}

## 严格要求
- 内容必须基于实际的Git提交记录，不得虚构或夸大
- 润色程度要适中，保持真实性和可信度
- ${format === 'text' ? '输出必须是纯文本，绝对不能包含任何Markdown标记符号' : '使用标准Markdown格式'}
- 语言要${style === 'professional' ? '专业且积极正面' : '简洁明了且突出成果'}`;
    }
  } else {
    if (style === 'simple') {
      // 简单风格周报：极简版本，只包含基本信息
      basePrompt = `请根据以下Git提交记录生成一份简洁的${reportType}：

## 提交记录
${commitDetails}

## 生成要求
请生成一份简洁的${reportType}，只包含：
- 本周完成的主要工作（2-3句话概括）
- 涉及的主要功能或模块
- 整体工作进展

## 写作要求
- 语言简洁直白，避免技术术语
- 重点说明完成了什么，解决了什么问题
- 内容控制在150字以内
- ${format === 'text' ? '使用纯文本格式，不使用任何标记符号' : '使用简单的Markdown格式'}`;
    } else {
      // 专业风格周报：适度润色版本，基于真实commit记录进行综合性表达优化
      basePrompt = `请根据以下Git提交记录生成一份${reportType}，对本周完成的工作进行适度润色：

## 团队贡献
${Object.entries(authorStats).map(([author, stats]: [string, any]) => {
  if (isGitChangeFormat) {
    return `- ${author}: ${stats.commits}次提交，${stats.changes}个文件变更`;
  } else {
    return `- ${author}: ${stats.commits}次提交`;
  }
}).join('\n')}

## 提交记录
${commitDetails}

## 生成要求
请基于上述提交记录生成一份${reportType}，重点包含以下内容：
1. **工作成果概览** - 从commit message中总结本周完成的主要工作和功能
2. **技术亮点** - 突出重要的技术实现、改进和创新点
3. **问题解决** - 说明修复了什么问题，带来了什么改善和优化
4. **功能特性** - 基于实际开发内容，适度阐述实现的功能价值
5. **工作总结** - 对本周整体工作进展进行积极正面的总结

## 润色要求
- 基于真实的commit记录进行适度润色，突出工作成果但不夸大
- 从commit message中提炼工作亮点和技术价值，保持真实性
- 用积极专业的语言表达工作成果，体现团队的专业能力
- 适度阐述功能价值，但避免过度包装和虚构内容
- 重点展现实际完成的工作，而非技术统计数据

## 写作风格要求
${styleRequirements}

## 格式要求
${formatRequirements}

## 严格要求
- 内容必须基于实际的Git提交记录，不得虚构或过度夸大
- 润色程度要适中，保持真实性和专业性
- 功能描述必须与commit message的实际内容对应
- 避免过度强调技术统计数据，重点突出工作成果
- ${format === 'text' ? '输出必须是纯文本，绝对不能包含任何Markdown标记符号' : '使用标准Markdown格式'}
- 语言要${style === 'professional' ? '专业且积极正面' : '简洁明了且突出成果'}`;
    }
  }

  // 如果有自定义提示词，追加到基础提示词后面
  let prompt = basePrompt;
  if (customPrompt && customPrompt.trim()) {
    prompt += `\n\n## 额外要求\n${customPrompt.trim()}`;
  }

  return prompt;
}

/**
 * 统一的AI API调用函数
 */
async function callAIAPI(prompt: string, config: AIConfig, format?: string): Promise<{ content: string; tokens: number }> {
  let result: { content: string; tokens: number };
  
  switch (config.provider) {
    case 'deepseek':
      result = await callDeepSeekAPI(prompt, config);
      break;
    case 'openai':
      result = await callOpenAIAPI(prompt, config);
      break;
    case 'tongyi':
      result = await callTongyiAPI(prompt, config);
      break;
    case 'doubao':
      result = await callDoubaoAPI(prompt, config);
      break;
    default:
      throw new Error(`不支持的AI服务商: ${config.provider}`);
  }
  
  // 如果是纯文本格式，后处理移除所有Markdown语法
  if (format === 'text') {
    result.content = removeMarkdownSyntax(result.content);
  }
  
  return result;
}

/**
 * 智能AI调用函数，支持多模型自动切换
 */
async function callSmartAI(prompt: string, multiConfig: MultiAIConfig, format?: string): Promise<AICallResult> {
  if (!multiConfig.autoSwitch || !multiConfig.models || multiConfig.models.length === 0) {
    throw new Error('多AI配置无效或未启用自动切换');
  }

  // 按优先级排序并过滤启用的模型
  const enabledModels = multiConfig.models
    .filter(model => model.enabled !== false)
    .sort((a, b) => (a.priority || 999) - (b.priority || 999));

  if (enabledModels.length === 0) {
    throw new Error('没有可用的AI模型');
  }

  let lastError: Error | null = null;
  let totalAttempts = 0;

  for (const model of enabledModels) {
    const maxRetries = model.maxRetries || 3;
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      totalAttempts++;
      
      try {
        console.log(`尝试使用模型: ${model.provider}/${model.model} (优先级: ${model.priority}, 第${attempt}次尝试)`);
        
        const result = await callAIAPI(prompt, model, format);
        
        console.log(`模型 ${model.provider}/${model.model} 调用成功`);
        
        return {
          content: result.content,
          tokens: result.tokens,
          usedModel: model,
          attempts: totalAttempts
        };
      } catch (error: any) {
        lastError = error;
        const errorMessage = error.message || error.toString();
        
        console.log(`模型 ${model.provider}/${model.model} 第${attempt}次调用失败: ${errorMessage}`);
        
        // 检查是否是配额耗尽错误
        const isQuotaError = isQuotaExhaustedError(errorMessage);
        
        if (isQuotaError && multiConfig.fallbackOnQuotaExhausted) {
          console.log(`检测到配额耗尽，跳过模型 ${model.provider}/${model.model}`);
          break; // 跳到下一个模型
        }
        
        // 检查是否是其他错误且启用了错误回退
        if (!isQuotaError && multiConfig.fallbackOnError && attempt === maxRetries) {
          console.log(`模型 ${model.provider}/${model.model} 达到最大重试次数，尝试下一个模型`);
          break; // 跳到下一个模型
        }
        
        // 如果不是最后一次尝试，等待一段时间后重试
        if (attempt < maxRetries) {
          const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000); // 指数退避，最大5秒
          console.log(`等待 ${delay}ms 后重试...`);
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }
  }

  // 所有模型都失败了
  throw new Error(`所有AI模型调用失败，总共尝试 ${totalAttempts} 次。最后错误: ${lastError?.message || '未知错误'}`);
}

/**
 * 检查错误是否为配额耗尽
 */
/**
 * 检查配置是否为多AI配置
 */
function isMultiAIConfig(config: AIConfig | MultiAIConfig): config is MultiAIConfig {
  return 'models' in config && Array.isArray((config as MultiAIConfig).models);
}

/**
 * 检查错误是否为配额耗尽
 */
function isQuotaExhaustedError(errorMessage: string): boolean {
  const quotaKeywords = [
    'quota',
    'limit',
    'exceeded',
    'insufficient',
    'balance',
    '配额',
    '余额',
    '不足',
    '超出',
    '限制',
    'rate limit',
    'too many requests'
  ];
  
  const lowerMessage = errorMessage.toLowerCase();
  return quotaKeywords.some(keyword => lowerMessage.includes(keyword.toLowerCase()));
}

/**
 * 合并分批处理的结果
 */
async function mergeBatchResults(
  batchResults: { content: string; tokens: number }[],
  type: string,
  config: AIConfig | MultiAIConfig,
  style?: string,
  format?: string
): Promise<string> {
  const reportType = type === 'daily' ? '日报' : '周报';
  const outputFormat = format === 'text' ? '纯文本' : 'Markdown';
  
  // 构建合并提示词
  const mergePrompt = `请将以下多个${reportType}片段合并成一份完整的${reportType}：

${batchResults.map((result, index) => `## 第${index + 1}部分\n${result.content}`).join('\n\n')}

## 合并要求
1. 将所有片段的内容整合成一份连贯的${reportType}
2. 去除重复的标题和结构
3. 按逻辑顺序重新组织内容
4. 保持${style === 'professional' ? '专业' : '简洁'}的写作风格
5. 使用${outputFormat}格式输出
6. 确保最终报告结构完整、逻辑清晰

请生成最终的完整${reportType}：`;
  
  let mergeResult: { content: string; tokens: number };
  if (isMultiAIConfig(config)) {
    const smartResult = await callSmartAI(mergePrompt, config, format);
    mergeResult = { content: smartResult.content, tokens: smartResult.tokens };
  } else {
    mergeResult = await callAIAPI(mergePrompt, config, format);
  }
  return mergeResult.content;
}

/**
 * 调用DeepSeek API
 */
async function callDeepSeekAPI(prompt: string, config: AIConfig): Promise<{ content: string; tokens: number }> {
  const baseUrl = config.baseUrl || 'https://api.deepseek.com/v1';
  
  const response = await fetch(`${baseUrl}/chat/completions`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${config.apiKey}`
    },
    body: JSON.stringify({
      model: config.model || 'deepseek-chat',
      messages: [
        {
          role: 'user',
          content: prompt
        }
      ],
      temperature: config.temperature || 0.7,
      max_tokens: config.maxTokens || 2000
    })
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`DeepSeek API调用失败: ${error}`);
  }

  const data = await response.json() as any;
  
  return {
    content: data.choices[0]?.message?.content || '生成失败',
    tokens: data.usage?.total_tokens || 0
  };
}

/**
 * 调用OpenAI API
 */
async function callOpenAIAPI(prompt: string, config: AIConfig): Promise<{ content: string; tokens: number }> {
  const baseUrl = config.baseUrl || 'https://api.openai.com/v1';
  
  const response = await fetch(`${baseUrl}/chat/completions`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${config.apiKey}`
    },
    body: JSON.stringify({
      model: config.model || 'gpt-3.5-turbo',
      messages: [
        {
          role: 'user',
          content: prompt
        }
      ],
      temperature: config.temperature || 0.7,
      max_tokens: config.maxTokens || 2000
    })
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`OpenAI API调用失败: ${error}`);
  }

  const data = await response.json() as any;
  
  return {
    content: data.choices[0]?.message?.content || '生成失败',
    tokens: data.usage?.total_tokens || 0
  };
}

/**
 * 调用通义千问API
 */
async function callTongyiAPI(prompt: string, config: AIConfig): Promise<{ content: string; tokens: number }> {
  const baseUrl = config.baseUrl || 'https://dashscope.aliyuncs.com';
  
  // 参数验证和调试日志
  console.log('通义千问API调用参数:', {
    model: config.model,
    temperature: config.temperature,
    maxTokens: config.maxTokens,
    baseUrl: baseUrl,
    promptLength: prompt.length
  });
  
  // 确保参数类型正确
  const temperature = typeof config.temperature === 'number' ? config.temperature : 0.7;
  const maxTokens = typeof config.maxTokens === 'number' ? config.maxTokens : 2000;
  const model = config.model || 'qwen-plus';
  
  // 验证必要参数
  if (!config.apiKey) {
    throw new Error('通义千问API密钥不能为空');
  }
  
  if (!prompt || prompt.trim() === '') {
    throw new Error('提示词不能为空');
  }
  
  // 构建请求体
  const requestBody = {
    model: model,
    input: {
      messages: [
        {
          role: 'user',
          content: prompt
        }
      ]
    },
    parameters: {
      result_format: 'message',
      temperature: temperature,
      max_output_tokens: maxTokens
    }
  };
  
  console.log('通义千问API请求体:', JSON.stringify(requestBody, null, 2));
  
  try {
    const apiUrl = `${baseUrl}/api/v1/services/aigc/text-generation/generation`;
    console.log('通义千问API请求URL:', apiUrl);
    
    const response = await fetch(apiUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${config.apiKey}`
      },
      body: JSON.stringify(requestBody)
    });

    console.log('通义千问API响应状态:', response.status, response.statusText);

    if (!response.ok) {
      const errorText = await response.text();
      console.error('通义千问API错误响应:', errorText);
      
      let errorMessage = `通义千问API调用失败 (${response.status}): ${errorText}`;
      
      // 尝试解析错误信息
      try {
        const errorData = JSON.parse(errorText);
        if (errorData.message) {
          errorMessage = `通义千问API调用失败: ${errorData.message}`;
        }
        if (errorData.code) {
          errorMessage += ` (错误代码: ${errorData.code})`;
        }
      } catch (parseError) {
        // 如果无法解析JSON，使用原始错误文本
      }
      
      throw new Error(errorMessage);
    }

    const data = await response.json() as any;
    console.log('通义千问API响应数据:', JSON.stringify(data, null, 2));
    
    // 验证响应格式
    if (!data.output || !data.output.choices || !Array.isArray(data.output.choices) || data.output.choices.length === 0) {
      console.error('通义千问API响应格式异常:', data);
      throw new Error('通义千问API响应格式异常：缺少output.choices数据');
    }
    
    const choice = data.output.choices[0];
    if (!choice.message || !choice.message.content) {
      console.error('通义千问API响应内容异常:', choice);
      throw new Error('通义千问API响应内容异常：缺少message.content数据');
    }
    
    return {
      content: choice.message.content,
      tokens: data.usage?.total_tokens || 0
    };
  } catch (error: any) {
    console.error('通义千问API调用异常:', error);
    throw error;
  }
}

/**
 * 调用豆包API
 */
async function callDoubaoAPI(prompt: string, config: AIConfig): Promise<{ content: string; tokens: number }> {
  // 构建API URL - 确保使用正确的火山引擎豆包API端点
  const baseUrl = config.baseUrl || 'https://ark.cn-beijing.volces.com/api/v3';
  const apiUrl = `${baseUrl}/chat/completions`;
  
  // 确保参数类型正确
  const temperature = typeof config.temperature === 'number' ? config.temperature : 0.7;
  const maxTokens = typeof config.maxTokens === 'number' ? config.maxTokens : 4000; // 提高默认值以支持包含diff的长文本
  const model = config.model || 'doubao-pro-4k';
  
  // 验证必要参数
  if (!config.apiKey) {
    throw new Error('豆包API密钥不能为空');
  }
  
  if (!prompt || prompt.trim() === '') {
    throw new Error('提示词不能为空');
  }
  
  // 检查提示词长度，防止超出token限制
  // 粗略估算：1个token约等于4个字符（中文）或0.75个单词（英文）
  const estimatedTokens = Math.ceil(prompt.length / 3); // 保守估算
  const maxInputTokens = Math.max(maxTokens * 0.7, 8000); // 为输出预留30%的token空间，最少8000
  
  if (estimatedTokens > maxInputTokens) {
    console.warn(`提示词过长，估算token数: ${estimatedTokens}, 最大允许: ${maxInputTokens}`);
    // 截断提示词，保留开头和结尾的重要信息
    const maxLength = Math.floor(maxInputTokens * 3); // 转换回字符数
    const keepStart = Math.floor(maxLength * 0.3); // 保留30%的开头
    const keepEnd = Math.floor(maxLength * 0.3); // 保留30%的结尾
    const truncatedPrompt = prompt.substring(0, keepStart) + 
      '\n\n[... 内容过长已截断 ...]\n\n' + 
      prompt.substring(prompt.length - keepEnd);
    console.log(`提示词已截断，原长度: ${prompt.length}, 新长度: ${truncatedPrompt.length}`);
    prompt = truncatedPrompt;
  }
  
  // 构建请求体（OpenAI兼容格式）
  const requestBody = {
    model: model,
    messages: [
      {
        role: 'user',
        content: prompt
      }
    ],
    temperature: temperature,
    max_tokens: maxTokens
  };
  
  // 构建请求头
  const headers = {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${config.apiKey}`
  };
  
  // 详细的调试日志
  console.log('=== 豆包API调用详情 ===');
  console.log('请求URL:', apiUrl);
  console.log('请求头:', JSON.stringify(headers, null, 2));
  console.log('请求体:', JSON.stringify(requestBody, null, 2));
  console.log('模型参数:', {
    model: model,
    temperature: temperature,
    maxTokens: maxTokens,
    promptLength: prompt.length,
    baseUrl: baseUrl
  });
  
  try {
    const response = await fetch(apiUrl, {
      method: 'POST',
      headers: headers,
      body: JSON.stringify(requestBody)
    });

    console.log('豆包API响应状态:', response.status, response.statusText);
    console.log('响应头:', Object.fromEntries(response.headers.entries()));

    if (!response.ok) {
      const errorText = await response.text();
      console.error('豆包API错误响应 (状态码:', response.status, '):', errorText);
      
      let errorMessage = `豆包API调用失败 (HTTP ${response.status})`;
      
      // 根据状态码提供更具体的错误信息
      if (response.status === 404) {
        errorMessage += ': API端点不存在。请检查：1) API URL是否正确 2) 模型ID是否有效 3) 是否需要使用Endpoint ID而不是Model ID';
      } else if (response.status === 401) {
        errorMessage += ': API密钥无效或已过期';
      } else if (response.status === 403) {
        errorMessage += ': 访问被拒绝，请检查API密钥权限';
      } else if (response.status === 429) {
        errorMessage += ': 请求频率超限，请稍后重试';
      } else if (response.status === 400) {
        errorMessage += ': 请求参数错误，可能是token数量超出限制或其他参数问题';
      } else if (response.status === 413) {
        errorMessage += ': 请求体过大，提示词内容超出限制';
      }
      
      // 尝试解析错误信息
      try {
        const errorData = JSON.parse(errorText);
        if (errorData.error) {
          if (errorData.error.message) {
            const errorMsg = errorData.error.message;
            // 检查是否是token限制相关错误
            if (errorMsg.includes('token') || errorMsg.includes('length') || errorMsg.includes('too long') || errorMsg.includes('exceed')) {
              errorMessage += ` - Token限制错误: ${errorMsg}。建议：1) 减少diff内容 2) 使用更高token限制的模型 3) 分批处理提交`;
            } else {
              errorMessage += ` - ${errorMsg}`;
            }
          }
          if (errorData.error.code) {
            errorMessage += ` (错误代码: ${errorData.error.code})`;
          }
        }
      } catch (parseError) {
        // 如果无法解析JSON，检查原始错误文本中的token相关关键词
        if (errorText) {
          const lowerErrorText = errorText.toLowerCase();
          if (lowerErrorText.includes('token') || lowerErrorText.includes('length') || lowerErrorText.includes('too long') || lowerErrorText.includes('exceed')) {
            errorMessage += ` - 疑似Token限制错误: ${errorText.substring(0, 200)}。建议减少diff内容或使用更高token限制的模型`;
          } else {
            errorMessage += ` - 原始错误: ${errorText.substring(0, 200)}`;
          }
        }
      }
      
      throw new Error(errorMessage);
    }

    const data = await response.json() as any;
    console.log('豆包API响应数据:', JSON.stringify(data, null, 2));
    
    // 验证响应格式（OpenAI兼容格式）
    if (!data.choices || !Array.isArray(data.choices) || data.choices.length === 0) {
      console.error('豆包API响应格式异常:', data);
      throw new Error('豆包API响应格式异常：缺少choices数据。响应可能不符合OpenAI格式标准。');
    }
    
    const choice = data.choices[0];
    if (!choice.message || !choice.message.content) {
      console.error('豆包API响应内容异常:', choice);
      throw new Error('豆包API响应内容异常：缺少message.content数据');
    }
    
    console.log('豆包API调用成功，返回内容长度:', choice.message.content.length);
    
    return {
      content: choice.message.content,
      tokens: data.usage?.total_tokens || 0
    };
  } catch (error: any) {
    console.error('=== 豆包API调用异常 ===');
    console.error('错误类型:', error.constructor.name);
    console.error('错误消息:', error.message);
    console.error('完整错误:', error);
    
    // 如果是网络错误，提供更有用的信息
    if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
      throw new Error(`豆包API网络连接失败: ${error.message}。请检查网络连接和API端点URL。`);
    }
    
    throw error;
  }
}

export default router;